/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 tabula.org
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package org.tablua.gamebox.model;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAttribute;

/**
 * Class representing a version number consisting of three parts, ie [major version].[minor version].[build number].
 * <br/>
 * <br/>
 * The major and minor versions are constrained to ordinals between 0 and 99, and the build number must be between 0 and 999.
 */
@XmlAccessorType(XmlAccessType.FIELD)
public class Version implements Comparable<Version> {

    @Min(0)
    @Max(99)
    @XmlAttribute(name = "major", required = true)
    private int majorVersion;

    @Min(0)
    @Max(99)
    @XmlAttribute(name = "minor", required = true)
    private int minorVersion;

    @Min(0)
    @Max(9999)
    @XmlAttribute(name = "build", required = true)
    private int buildNumber;

    /**
     * Private default constructor. Needed for JAXB serialization.
     */
    private Version() { }

    /**
     * Constructor with constrained version ranges.
     *
     * @param majorVersion major version. Prohibited to a ordinal range between 0 and 99.
     * @param minorVersion minor version. Prohibited to a ordinal range between 0 and 99.
     * @param buildNumber  build number. Prohibited to a ordinal range between 0 and 9999.
     */


    public Version(int majorVersion, int minorVersion, int buildNumber) {
        this.majorVersion = majorVersion;
        this.minorVersion = minorVersion;
        this.buildNumber = buildNumber;
    }

    /**
     * Returns the most significant version number. Different major versions are typically not compatible.
     *
     * @return the major version number.
     */
    public int getMajorVersion() {
        return majorVersion;
    }

    /**
     * Returns the minor version number. Increases in minor version number typically signifies small changes and new features.
     * Increases in minor versions doesn't typically prohibit compatibility with previous minor versions.
     *
     * @return the minor version number.
     */
    public int getMinorVersion() {
        return minorVersion;
    }

    /**
     * Returns the minor build number. Increases in small changes like bug fixes.
     * Increases in build number never changes compatibility with previous builds.
     *
     * @return the build number.
     */
    public int getBuildNumber() {
        return buildNumber;
    }

    /**
     * Returns a version string in the format [major version].[minor version].[build number]
     *
     * @return formatted version string.
     */
    @Override
    public String toString() {
        return new StringBuilder().append(majorVersion).append('.').append(minorVersion).append('.').append(buildNumber).toString();
    }

    /**
     * Implementation of <code>Comparable</code>. Allows for comparing versions.
     *
     * @see Comparable
     */
    @Override
    public int compareTo(Version compareTo) {
        if (this.getFactoredVersion() == compareTo.getFactoredVersion()) {
            return 0;
        } else if (this.getFactoredVersion() > compareTo.getFactoredVersion()) {
            return 1;
        } else {
            return -1;
        }
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Version) {
            Version equalsVersion = (Version) obj;
            return equalsVersion.getMajorVersion() == majorVersion && equalsVersion.getMinorVersion() == minorVersion &&
                    equalsVersion.buildNumber == buildNumber;
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return getFactoredVersion();
    }

    /**
     * Utility function for calculating factored version, allowing for easy comparsion.
     *
     * @return factored version number (major * 100000 + minor * 1000 + build).
     */
    private int getFactoredVersion() {
        int majorFactor = (majorVersion + 1) * 100000;
        int minorFactor = (minorVersion + 1) * 1000;
        return majorFactor + minorFactor + getBuildNumber();
    }

}
